package vip.web3.api.interceptor;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import vip.web3.api.annotation.RequestLog;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * <ul>
 * <li>文件包名 : com.example.currency.message</li>
 * <li>创建时间 : 2019/6/13 11:44</li>
 * <li>修改记录 : 无</li>
 * </ul>
 * 类说明：请求日志统一拦截 打印
 *
 * aut-horllj
 * @version 1.0.0
 */
@Component
@Aspect
public class RequestLogInterceptor {

    public static final Logger LOG = LoggerFactory.getLogger(RequestLogInterceptor.class);

    /**
     * Define a pointcut
     */
    @Pointcut("@annotation(vip.web3.api.annotation.RequestLog)")
    public void controllerLog() {
    }

    /**
     * Print Log before controller
     *
     * @param joinPoint
     */
    @Before("controllerLog()")
    public void before(JoinPoint joinPoint) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        LOG.info("请求IP：{}", request.getRemoteAddr());
        LOG.info("请求路径：{}", request.getRequestURL());
        LOG.info("请求方式：{}", request.getMethod());
        LOG.info("方法描述：{}", getMethodDescription(joinPoint));
        LOG.info("请求参数：{}", JSONObject.toJSONString(request.getParameterMap()));

    }

    /**
     * Print the time that request method execution spend
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around("controllerLog()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object[] args = joinPoint.getArgs();
        Object retVal = joinPoint.proceed(args);
        long endTime = System.currentTimeMillis();
        LOG.info("执行时间：{} ms", endTime - startTime);
        LOG.info("返回值：{}\n\t", JSONObject.toJSON(retVal));
        return retVal;
    }

    /**
     * Print exception
     *
     * @param ex
     */
    @AfterThrowing(throwing = "ex", pointcut = "controllerLog()")
    public void afterThrowing(Throwable ex) {
        LOG.error("发生异常：{}", ex.toString());
    }

    /**
     * Acquire the description for annotation target method
     *
     * @param joinPoint
     * @return
     * @throws Exception
     */
    protected String getMethodDescription(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class<?> targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();

        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class<?>[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description = method.getAnnotation(RequestLog.class).description();
                    break;
                }
            }
        }
        return description;
    }
}
